﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Reflection;

namespace Optimization.Experiment
{
    public class LibTester: MarshalByRefObject
    {
        //http://malvinly.com/2012/04/08/executing-code-in-a-new-application-domain/


        public Func<Type, bool> queryFunc = null;


        public List<string> Query(Func<Type, bool> queryFunc, string[] assembliesToTest)
        {
            AppDomain workerAppDomain = AppDomain.CreateDomain("Test" + Guid.NewGuid());

            if (queryFunc == null)
                this.queryFunc = t => true;
            else
                this.queryFunc = queryFunc;

            Type libsQueryType = typeof(LibTester);
            LibTester test = (LibTester)workerAppDomain.CreateInstanceAndUnwrap(libsQueryType.Assembly.GetName().Name, libsQueryType.FullName);
            test.queryFunc = this.queryFunc;

            List<string> result = test.RemoteMethod(assembliesToTest);

            AppDomain.Unload(workerAppDomain);
            return result;
        }

        private List<string> RemoteMethod(string[] assembliesToTest)
        {
            List<string> result = new List<string>();
            //result.Add("Done in domain");
            //result.Add(AppDomain.CurrentDomain.FriendlyName);

            foreach (string aName in assembliesToTest)
            {
                Assembly assemblyInstance = Assembly.LoadFrom(aName);

                Type[] types = null;
                try
                {
                    types = assemblyInstance.GetTypes();
                }
                catch (ReflectionTypeLoadException e)
                {
                    types = e.Types.Where(t => t != null).ToArray();
                }

                foreach (Type t in types)
                {
                    if (queryFunc(t))
                        result.Add(t.AssemblyQualifiedName);
                }
            }

            return result;
        }
    }
}
